package treeedit;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
//import java.io.FileFilter;

import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.TreePath;

import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;



public class Main extends JFrame
{
	private static Configuration configuration = Configuration.getInstance();
	
	private enum ViewState {
		TREE,LISP,HORIZONTAL,VERTICAL
	}
	
	
	private ViewState viewState = ViewState.HORIZONTAL;
	private JMenuBar bar;
	private ActionListener listener = new MyActionListener();
	private CodeTree tree = new CodeTree(new CodeModelExtra());
	private JLispConsole console = new JLispConsole();
	private JPanel status = new JPanel();
	private JLabel mode = new JLabel();
	private JLabel panel = new JLabel("status bar");
	private JPanel treePanel = new JPanel();
	private JPanel consolePanel = new JPanel();
	private JPanel horizontalPanel = new JPanel();
	private JPanel verticalPanel = new JPanel();
	private Messanger messanger = Messanger.getInstance(panel);
	
	
	
	private static final Object FileMenu[][] = { 
		{"New",KeyStroke.getKeyStroke('N',8),"new" } ,
		{"Open",KeyStroke.getKeyStroke('O',8),"open" },
		{"Save",KeyStroke.getKeyStroke('S',8),"save" } ,
		{null},
		{configuration.getRecentFile(0),null,"recent"},
		{configuration.getRecentFile(1),null,"recent"},
		{configuration.getRecentFile(2),null,"recent"},
		{null},
		{"Exit",KeyStroke.getKeyStroke('X',8),"exit" } 
		};
	
	
	private static final Object EditMenu[][] = { 
		{"Start next",KeyStroke.getKeyStroke("SPACE"),"start_next" } ,
		{"Start before",KeyStroke.getKeyStroke("control typed h"),"start_before" } ,
		{"Start into",KeyStroke.getKeyStroke("control typed e"),"start_into" } ,
		{"Pop up intelli sense",KeyStroke.getKeyStroke(' ',2),"sense" },
		{"Delete node",KeyStroke.getKeyStroke("DELETE"),"delete" } ,
		{"Expand all",KeyStroke.getKeyStroke("F1"),"expand"},
		{"Collapse all",KeyStroke.getKeyStroke("F2"),"collapse"},
		{"Mark",KeyStroke.getKeyStroke("control typed c"),"mark"},
		{"Insert into",KeyStroke.getKeyStroke("control typed v"),"insert_into"},
		{"Insert before",KeyStroke.getKeyStroke("control typed b"),"insert_before"},
		{"Insert after",KeyStroke.getKeyStroke("control typed a"),"insert_after"},
		{"Exchange",KeyStroke.getKeyStroke("control typed x"),"exchange"},
		{"Surround",KeyStroke.getKeyStroke("control typed i"),"surround"},
		{"Unsurround",KeyStroke.getKeyStroke("control typed o"),"unsurround"},
		{"Paste",KeyStroke.getKeyStroke("control typed p"),"paste"},
		{"To/from string",KeyStroke.getKeyStroke("control typed s"),"string"},
		{"To/from quote",KeyStroke.getKeyStroke("control typed q"),"quote"},
		
	};

	private static final Object RunMenu[][] = { 
		{"Run clisp",KeyStroke.getKeyStroke("control F5"),"run_clisp"},
		{"Run program",KeyStroke.getKeyStroke("control F6"),"run_program"},
		{"Kill clisp",KeyStroke.getKeyStroke("control F7"),"kill"},
		{"Clear console",KeyStroke.getKeyStroke("control F8"),"clear"},
		{"Clisp path",KeyStroke.getKeyStroke("control F9"),"path"},
		
	};
	
	private static final Object ViewMenu[][] = { 
		{"Only tree",KeyStroke.getKeyStroke("control F1"),"tree"},
		{"Only console",KeyStroke.getKeyStroke("control F2"),"console"},
		{"Horizonal Split",KeyStroke.getKeyStroke("control F3"),"horizontal"},
		{"Vertival Split",KeyStroke.getKeyStroke("control F4"),"vertical"},

	};

	private static final Object HelpMenu[][] = { 
		{"Help",KeyStroke.getKeyStroke("control F10"),"help"},
		{null},
		{"About",KeyStroke.getKeyStroke("control F11"),"about"},
	};

	
	public Main (Splash s )
	{
		super("Tree-Edit");
		
		setPreferredSize(configuration.getDimensions());
//		System.out.println(configuration.getLocation());
		setLocation(configuration.getLocation());
		
		addWindowListener(new MyWindowAdapter());
		
		//Preparing status
		status.setLayout(new GridLayout(1,2));
		status.add(panel);
		status.add(mode);
		status.setBorder(BorderFactory.createEtchedBorder());
		
		
		createMenuBar();
	
			
//		System.err.println("COUNT=" + configuration.getRecentFileCount());
		
		this.setJMenuBar(bar);
	
		changeView(ViewState.HORIZONTAL);
		
		tree.clear();
		
		setVisible(true);
		synchronized (s) 
		{
			s.notify();
		}
		
	}
	
	private void createMenuBar()
	{
		//Creating menu bar
		bar = new JMenuBar();
		
		bar.add(createMenu("File", FileMenu,KeyEvent.VK_F));
		bar.add(createMenu("Edit",EditMenu, KeyEvent.VK_E));
		bar.add(createMenu("View",ViewMenu,KeyEvent.VK_V));
		bar.add(createMenu("Run",RunMenu, KeyEvent.VK_R));
		bar.add(createMenu("Help", HelpMenu,KeyEvent.VK_H));
		
		setJMenuBar(bar);
		
	}

	private JMenu createMenu(String name,Object [][]array,int k)
	{
		JMenu menu = new JMenu(name);
		menu.setMnemonic(k);
		for(int i = 0; i < array.length; i++)
		{
			if(array[i][0] == null && array[i].length == 1)
			{
				menu.addSeparator();
				continue;
			}
			if(array[i][0] == null) continue;
			JMenuItem item = new JMenuItem(array[i][0].toString());
			item.addActionListener(listener);
			if(array[i][1] != null )item.setAccelerator((KeyStroke)array[i][1]);
			item.setActionCommand(array[i][2].toString());
			menu.add(item);
		}
		menu.addActionListener(listener);
		return menu;
		
	}
	
	private void clearPanes()
	{
		treePanel.removeAll();

		consolePanel.removeAll();

		horizontalPanel.removeAll();

		verticalPanel.removeAll();
	
	}
	
	private void changeView(ViewState state)
	{
		clearPanes();
		if(state == ViewState.TREE)
		{
			mode.setText("Mode: Tree");
			messanger.setMessage("Changing mode...",1000);
			
			treePanel.setLayout(new BorderLayout());
			treePanel.add(new JScrollPane(tree),BorderLayout.CENTER);
			treePanel.add(status,BorderLayout.SOUTH);
			
			
			setContentPane(treePanel);
			pack();			
		}
		else if(state == ViewState.LISP)
		{
			mode.setText("Mode: Clisp");
			messanger.setMessage("Changing mode...",1000);
			
			
			consolePanel.setLayout(new BorderLayout());
			consolePanel.add(new JScrollPane(console),BorderLayout.CENTER);
			consolePanel.add(status,BorderLayout.SOUTH);
			
			setContentPane(consolePanel);
			pack();			
		
		}
		if(state == ViewState.HORIZONTAL)
		{
			JSplitPane split;
			
			mode.setText("Mode: Horizontal");
			messanger.setMessage("Changing mode...",1000);
						
			horizontalPanel.setLayout(new BorderLayout());
			horizontalPanel.add(split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,new JScrollPane(tree),new JScrollPane(console)),BorderLayout.CENTER);
			horizontalPanel.add(status,BorderLayout.SOUTH);
			setContentPane(horizontalPanel);
			pack();	
			
			split.setDividerLocation(split.getWidth() / 2);
			
		
		}if(state == ViewState.VERTICAL)
		{
			JSplitPane split;
						
			mode.setText("Mode: Vertical");
			messanger.setMessage("Changing mode...",1000);
			
			verticalPanel.setLayout(new BorderLayout());
			verticalPanel.add(split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,new JScrollPane(tree),new JScrollPane(console)),BorderLayout.CENTER);
			verticalPanel.add(status,BorderLayout.SOUTH);
			
			setContentPane(verticalPanel);
			pack();	
			
			split.setDividerLocation(split.getHeight() / 2);
			
			
		}
			
	}
	
	class MyActionListener implements ActionListener 
	{

		public void actionPerformed(ActionEvent e) {
//			System.out.println("ACTION");
			String action = e.getActionCommand();
			
			if(action.equals("tree"))
			{
				changeView(viewState.TREE);
			}
			else if(action.equals("console"))
			{
				changeView(viewState.LISP);
			}
			else if(action.equals("horizontal"))
			{
				changeView(viewState.HORIZONTAL);
			}
			else if(action.equals("vertical"))
			{
				changeView(viewState.VERTICAL);
			}
			//IO
			else if(action.equals("open"))
			{
				openFile();
			}
			else if(action.equals("save"))
			{
				saveFile();
			}
			else if(action.equals("new"))
			{
				messanger.setMessage("New File",3000);
				tree.clear();
			}
			//Run
			else if(action.equals("run_clisp"))
			{
				console.kill();
				try {
					console.runFromFile(" ");
					messanger.setMessage("Run clisp",3000);
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					messanger.setError("Running clisp failed", 5000);
					e1.printStackTrace();
					
				}
			}
			else if(action.equals("run_program"))
			{
			
				System.out.println("Running clisp program");
				console.kill();
				try
				{
					console.runFromString(((CodeNode) ((CodeModel)tree.getModel()).getRoot()).getFileContent());
					//console.runFromFile(" /home/obiwan/print.lsp");
					messanger.setMessage("Run clisp",3000);
				}
				catch ( IOException ex )
				{
					messanger.setError("Running clisp failed", 5000);
					ex.printStackTrace();
				}
						
			}
			else if(action.equals("kill"))
			{
				console.kill();
			}
			else if(action.equals("clear"))
			{
				console.setText("");
			}
			else if(action.equals("exit"))
			{
				shutdown();
			}
			else if(action.equals("help"))
			{
				JOptionPane.showMessageDialog(null, "Please send your credit card number for further assistance :)");
			}
			else if(action.equals("path"))
			{
				new PathChanger();
			}
			else if(action.equals("recent"))
			{
				openFile(((JMenuItem)e.getSource()).getText());
			}
			
			//Checking for tree functions
			boolean in = false;;
			TreePath path = tree.getSelectionPath();
			
			if(console.isFocusOwner()) return ;
			
			if(action.equals("start_next"))
			{
				//System.err.println("start_next");
				in = true;
				//tree.setFocusable(true);
				if(path != null)
				{
					tree.reactInsertAndStartEditingBrotherNode(e);
					return ;
				}
			}
			if(action.equals("start_before"))
			{
				//System.err.println("start_next");
				in = true;
				//tree.setFocusable(true);
				if(path != null)
				{

					tree.reactEditNewBefore(e);
					return ;
				}
			}
			if(action.equals("start_into"))
			{
				//System.err.println("start_next");
				in = true;
				//tree.setFocusable(true);
				if(path != null)
				{
					tree.reactEditNewInside(e);
					return ;
				}
			}
			if(action.equals("sense"))
			{
				//System.err.println("start_next");
				in = true;
				//tree.setFocusable(true);
				if(tree.isEditing())
				{
					tree.getEditor().reachShowSense(tree.getEditor());
					return ;
				}
			}
			if(action.equals("expand"))
			{
				in = true;
				if(path != null)
				{
					tree.expandAll();
					return ;
				}
			}
			if(action.equals("collapse"))
			{
				in = true;
				if(path != null)
				{
					tree.collapseAll();
					return ;
				}
			}
			if(action.equals("delete"))
			{
				in = true;
				if(path != null)
				{
					tree.reactDeleteSelectedNode(e);
					return ;
				}
			}
			if(action.equals("mark"))
			{
				in = true;
				if(path != null)
				{
					tree.reactMarkedNode(e);
					return ;
				}
			}
			if(action.equals("insert_into"))
			{
				in = true;
				if(path != null)
				{
					tree.reactInsertInto(e);
					return ;
				}
			}
			if(action.equals("insert_before"))
			{
				in = true;
				if(path != null)
				{
					tree.reactInsertBefore(e);
					return ;
				}
			}
			if(action.equals("exchange"))
			{
				in = true;
				if(path != null)
				{
					tree.reactExchange(e);
					return ;
				}
			}
			if(action.equals("surround"))
			{
				in = true;
				if(path != null)
				{
					tree.reactParenthesisIn(e);
					return ;
				}
			}
			if(action.equals("unsurround"))
			{
				in = true;
				if(path != null)
				{
					tree.reactParenthesisOut(e);
					return ;
				}
			}
			if(action.equals("paste"))
			{
				in = true;
				if(path != null)
				{
					tree.reactPaste(e);
					return ;
				}
			}
			if(action.equals("string"))
			{
				in = true;
				if(path != null)
				{
					tree.reactStringify(e);
					return ;
				}
			}
			if(action.equals("quote"))
			{
				in = true;
				if(path != null)
				{
					tree.reactQuote(e);
					return ;
				}
			}
			if(action.equals("about"))
			{
				new About("clipart.png",null);
			}

			if(in)
			{
				
				if(path == null) 
				{
					messanger.setMessage("Please select path...",3000);
					return ;
				}
			}
			
			
			
			//Open, Save, New Actions
			
		}
		
		
	}
	
	class MyWindowAdapter extends WindowAdapter
	{

		@Override
		public void windowClosing(WindowEvent e) 
		{
			shutdown();
		}
		
	}
	
	
	public void openFile( String filename)
	{
		try {
			tree.load(filename);
			messanger.setMessage("Loaded File",2000);
		} catch (IOException e) {
			messanger.setError("Could not load file: IO problem", 5000);
			e.printStackTrace();
		} catch (ParseException e) {
			messanger.setError("Could not load file: Parse problem", 5000);
			e.printStackTrace();
		}
	}
	
	public void openFile( )
	{
		JFileChooser chooser = new JFileChooser();
		//chooser.setFileFilter(
		
		
		javax.swing.filechooser.FileFilter f = new javax.swing.filechooser.FileFilter (){
			public boolean accept(File file)
			{
				return (file.isDirectory()) ||  (file.getName().endsWith(".lsp"));
			}

			@Override
			public String getDescription() {
				// TODO Auto-generated method stub
				return "*.lsp";
			}
			};
		chooser.setFileFilter(f);
	
		int choice = chooser.showOpenDialog(this);
		
		if(choice == JFileChooser.APPROVE_OPTION)
		{
			try {
				tree.load(chooser.getSelectedFile().getAbsolutePath());
				messanger.setMessage("Loaded File",2000);
				configuration.addRecentFile(chooser.getSelectedFile().getAbsolutePath());
			} catch (IOException e) {
				messanger.setError("Could not load file: IO problem", 5000);
				e.printStackTrace();
			} catch (ParseException e) {
				messanger.setError("Could not load file: Parse problem", 5000);
				e.printStackTrace();
			}
			
		}
		
		
	}

	public void saveFile( )
	{
		JFileChooser chooser = new JFileChooser();
		//chooser.setFileFilter(


		javax.swing.filechooser.FileFilter f = new javax.swing.filechooser.FileFilter (){
			public boolean accept(File file)
			{
				return (file.isDirectory()) ||  (file.getName().endsWith(".lsp"));
			}

			@Override
			public String getDescription() {
				// TODO Auto-generated method stub
				return "*.lsp";
			}
		};
		chooser.setFileFilter(f);

		int choice = chooser.showSaveDialog(this);

		if(choice == JFileChooser.APPROVE_OPTION)
		{
			String path = chooser.getSelectedFile().getAbsolutePath();
			if(!path.endsWith(".lsp")) path +=".lsp";
			try {
				tree.save(path);
				messanger.setMessage("Saved file", 5000);
				configuration.addRecentFile(path);
				} catch (IOException e) {
				messanger.setError("Failed to save file", 5000);
				e.printStackTrace();
				
			}
			
		}
	}

	
	public static void main (String args[])
	{
		final Splash s = new Splash("clipart.png",null);
		SplashRun run = new SplashRun(s);
		
		run.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		SwingUtilities.invokeLater(new Runnable() 
		{
			public void run()
			{
				new Main(s);
			}
		}) ;

	}
	
	public void shutdown()
	{
		configuration.setLocation(getLocation());
//		System.out.println(getLocation());
		configuration.setDimensions(getSize());
	//	configuration.setLispPath("aaa");
		configuration.store();
		System.exit(0);
	}

	
}
